#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>

#include "TFly_list.h"
#include "script_func.h"
#include "script_expression.h"
#include "script.h"
#include "script_debug.h"
#include "script_include.h"
#include "script_keyword.h"
#include "script_stack.h"
#include "script_var.h"
#include "regex.h"

#define SESSION_DEBUG(x,y...)

static TFly_list_t *default_func_list = NULL;
exp_var_t default_func_var = {
	.type = EXP_VAR_TYPE_STRUCT,
};

int script_func_arg_get(TFly_list_t *args,script_stack_t *block_stack, int argc, exp_node_t **arg)
{
	if(args == NULL || argc == 0 || arg == NULL){
		return -1;
	}

	exp_node_t *_node = TFly_list_get_first(args);
	if(_node == NULL){
		return -2;
	}

	exp_node_t *node = expression_calc(_node,block_stack);
	if(node == NULL){
		return -3;
	}

	arg[0] = node;

	int i;
	for(i = 1; i < argc; i++){
		_node = TFly_list_get_next(args);
		if(_node == NULL){
			break;
		}
		node = expression_calc(_node,block_stack);
		if(node == NULL || node->type == EXP_NODE_TYPE_ERR){
			SCRIPT_DEBUG_ERR("Get function arg %d fail",i);
			arg[i] = node;
			break;
		}
		arg[i] = node;
	}

	return i;
}

void  script_func_arg_release(int argc, exp_node_t **arg)
{
	if(arg == NULL || argc <= 0){
		return;
	}
	int i;
	for(i = 0; i < argc; i++){
		if(arg[i]){
			exp_node_destroy(arg[i]);
		}
	}
	return;
}

static exp_node_t *sn_printf(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
    exp_node_type_e type;
    int value_int;
    char *value_str;
	double value_d;

	exp_node_t *result;
	exp_node_t *node = TFly_list_get_first(args);
	int flag = 0;
	printf("Print: ");
    while (node) {
		if(flag){
			printf("       ");
		}
		flag = 1;
		result = expression_calc(node,block_stack);
		CHECK_RESULT(result);	
		if(result->type == EXP_NODE_TYPE_VAR){
			exp_var_t *var = exp_var_point_take(result->var);
			printf("[var]  ");
			show_exp_var(var,0);
		}else{
			get_exp_node_value(result, &type, &value_str, &value_int,&value_d);
		
			switch (type) {
				case EXP_NODE_TYPE_CONST_INT:
					printf("%d",value_int);
					break;
				case EXP_NODE_TYPE_CONST_DOUBLE:
					printf("%f",value_d);
					break;
				case EXP_NODE_TYPE_CONST_STRING:
					printf("%s",value_str);
					break;
				case EXP_NODE_TYPE_CONST_NULL:
					printf("NULL");
					break;
				default:
					break;
			}
			printf("\n");
		}
		node = TFly_list_get_next(args);
		exp_node_destroy(result);
	}


    return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
}

static exp_node_t *new_struct(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
    exp_node_t *node = script_calloc(1, sizeof(exp_node_t));
	node->type = EXP_NODE_TYPE_VAR;	
	exp_node_t *arg = TFly_list_get_first(args);
	if(arg == NULL){
		node->var = exp_var_parse(NULL,"{}");
	}else{
		exp_node_t *result = expression_calc(arg,block_stack);
		if(result == NULL || result->type == EXP_NODE_TYPE_ERR){
			exp_node_destroy(node);
			return result;
		}
		char *str = exp_node_to_string(result);
		node->var = exp_var_parse(NULL,str);
		if(node->var == NULL){
			SCRIPT_DEBUG_ERR("NewStruct parse fail");
			node->type = EXP_NODE_TYPE_ERR;
		}
		script_free(str);
		exp_node_destroy(result);
	}
	return node;
}

static exp_node_t *struct_member_delete(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}
	
	exp_node_t *arg[2] = {0};

	int argc = script_func_arg_get(args,block_stack,2,arg);

	exp_node_t *array = arg[0];
	exp_node_t *value = arg[1];
	exp_node_t *result = NULL;
	if(array == NULL || value == NULL){
		SCRIPT_DEBUG_ERR("MemberDelete param calc fail");
		goto exit;
	}
	
	if(array->type != EXP_NODE_TYPE_VAR){
		SCRIPT_DEBUG_ERR("MemberDelete param fail, first argument must be struct type");
		result = exp_node_create(EXP_NODE_TYPE_ERR,NULL);
		goto exit;
	}

	exp_var_t *var = exp_var_point_take(array->var);
	if(var->type != EXP_VAR_TYPE_STRUCT){
		SCRIPT_DEBUG_ERR("MemberDelete param fail, first argument must be struct type");
		result = exp_node_create(EXP_NODE_TYPE_ERR,NULL);
		goto exit;
	}

	char *str;
	int index;
	exp_node_type_e type;
	get_exp_node_value(value,&type,&str,&index,NULL);
	if(type == EXP_NODE_TYPE_CONST_STRING){
		exp_var_struct_delete(var,str);
	}else if(type == EXP_NODE_TYPE_CONST_INT){
		exp_var_array_delete(var,index);
	}else{
		SCRIPT_DEBUG_ERR("MemberDelete param fail, second argument must be string type");
		goto exit;
	}

	
	result = exp_node_create(EXP_NODE_TYPE_CONST_INT,0);
	
exit:
	script_func_arg_release(argc,arg);
	return result;
}

static exp_node_t *sn_random(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_type_e type;
    int		start_num = 0;
    int		end_num = 0;
    exp_node_t *node = NULL;
    struct timeval tv; 

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("Random param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}
	
    get_exp_node_value(arg[0], &type, NULL, &start_num,NULL);
    if (type != EXP_NODE_TYPE_CONST_INT) {
		goto error;
    }

	get_exp_node_value(arg[1], &type, NULL, &end_num,NULL);
	if (type != EXP_NODE_TYPE_CONST_INT) {
		goto error;
	}

	int num = 0;
	if (end_num < start_num) {
		num = start_num;
	} else {
	    gettimeofday(&tv,NULL);
	    srandom(tv.tv_sec);
		num = random()%(end_num - start_num + 1) + start_num;
    }
	node = exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)num);

	script_func_arg_release(argc,arg);
    return node;

error:
	script_func_arg_release(argc,arg);
	SCRIPT_DEBUG_ERR("Random run fail");
	return NULL;
}

static exp_node_t *string_to_number(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;
	}

	exp_node_t *value = TFly_list_get_first(args);
	if(value == NULL){
		return NULL;
	}

	exp_node_t *_value = expression_calc(value,block_stack);
	CHECK_RESULT(value);
	exp_node_t *result = NULL;

	exp_node_type_e type;
	char *str;
	int num;
	get_exp_node_value(_value,&type,&str,&num,NULL);

	if(type == EXP_NODE_TYPE_CONST_STRING){
		num = strtol(str,NULL,0);
		result = exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)num);
	}else if(type == EXP_NODE_TYPE_CONST_INT){
		result = exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)num);
	}else{
		result = exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
	}

	exp_node_destroy(_value);
	return result;
}

static exp_node_t *sn_to_string(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;
	}

	exp_node_t *value = TFly_list_get_first(args);
	if(value == NULL){
		return NULL;
	}

	exp_node_t *_value = expression_calc(value,block_stack);
	CHECK_RESULT(_value);
	exp_node_t *result = NULL;

	char *buf = exp_node_to_string(_value);
	if(buf){
		result = exp_node_create(EXP_NODE_TYPE_CONST_STRING,NULL);
		result->string = buf;
	}else{
		result = exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
	}

	exp_node_destroy(_value);
	return result;
}

static exp_node_t *sn_length(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *value = TFly_list_get_first(args);
	if(value == NULL){
		return NULL;
	}
	int len = 0;

	exp_node_t *_value = expression_calc(value,block_stack);
	CHECK_RESULT(_value);
	exp_node_t *result = NULL;

	exp_node_type_e type;
	char *str;
	int num;
	get_exp_node_value(_value,&type,&str,&num,NULL);
	if(type == EXP_NODE_TYPE_CONST_STRING){
		len = strlen(str);
	}else if(type == EXP_NODE_TYPE_VAR){
		exp_var_t *var = exp_var_point_take(_value->var);
		if(var && (var->type == EXP_VAR_TYPE_ARRAY ||
				var->type == EXP_VAR_TYPE_STRUCT)){
			len = exp_var_size(var);
		}
	}
	exp_node_destroy(_value);	
	result = exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)len);

	return result;
}

static exp_node_t *sn_var_type_get(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *value = TFly_list_get_first(args);
	if(value == NULL){
		return NULL;
	}

	exp_node_t *_value = expression_calc(value,block_stack);
	CHECK_RESULT(_value);
	if(_value->type != EXP_NODE_TYPE_VAR){
		exp_node_destroy(_value);
		return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"unknow");
	}
	exp_var_t *var = exp_var_point_take(_value->var);
	if(var == NULL){
		exp_node_destroy(_value);
		return NULL;
	}
	script_var_type_e type = var->type;
	exp_node_destroy(_value);
	switch(type){
		case EXP_VAR_TYPE_INT:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"int");
		case EXP_VAR_TYPE_STRING:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"string");
		case EXP_VAR_TYPE_DOUBLE:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"double");
		case EXP_VAR_TYPE_STRUCT:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"struct");
		case EXP_VAR_TYPE_ARRAY:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"array");
		case EXP_VAR_TYPE_FUNCTION:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"function");
		case EXP_VAR_TYPE_C_VAR:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"c_var");
		case EXP_VAR_TYPE_FALSE:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"false");
		case EXP_VAR_TYPE_TRUE:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"true");
		default:
			return exp_node_create(EXP_NODE_TYPE_CONST_STRING,"unknow");

	}
	return NULL;
}

static exp_node_t *sn_sleepm(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *value = TFly_list_get_first(args);
	if(value == NULL){
		return NULL;
	}

	exp_node_t *_value = expression_calc(value,block_stack);
	CHECK_RESULT(_value);
	int ms = 0;
	exp_node_type_e type;
	get_exp_node_value(_value,&type,NULL,&ms,NULL);
	
	if(type != EXP_NODE_TYPE_CONST_INT){
		exp_node_destroy(_value);
		return NULL;
	}
	exp_node_destroy(_value);
	usleep(ms*1000);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
}

static exp_node_t *sn_time(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg = TFly_list_get_first(args);
	exp_node_t *result = NULL;
	int num = -1;
	if(arg){
		result = expression_calc(arg,block_stack);
		CHECK_RESULT(result);
		exp_node_type_e type;
		get_exp_node_value(result,&type,NULL,&num,NULL);
		exp_node_destroy(result);

	}

	struct timeval tv = {0};
	struct tm *tm = NULL;
	if(num >= 0){
		tv.tv_sec = num;
	}else{
		gettimeofday(&tv,NULL);
	}
	tm = localtime(&tv.tv_sec);
	
    exp_node_t *node = script_calloc(1, sizeof(exp_node_t));
	node->type = EXP_NODE_TYPE_VAR;	
	char str[128] = {0};
	sprintf(str,"{\"timestamp_sec\":%ld,\"msec\":%ld,\"year\":%d,\"month\":%d,\"day\":%d,\"week\":%d,\"hour\":%d,\"minute\":%d,\"second\":%d}",tv.tv_sec,tv.tv_usec/1000,tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_wday,tm->tm_hour,tm->tm_min,tm->tm_sec);
	node->var = exp_var_parse(NULL,str);

	return node;
}

static exp_node_t *array_insert(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[3] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,3,arg);
	if(argc < 3){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *array = arg[0];
	exp_node_t *index = arg[1];
	exp_node_t *value = arg[2];

	exp_node_t *result = NULL;
	
	if(array->type != EXP_NODE_TYPE_VAR){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, first argument must be array type");
		return NULL;
	}

	exp_var_t *var = exp_var_point_take(array->var);
	if(var->type != EXP_VAR_TYPE_ARRAY){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, first argument must be array type");
		goto exit;
	}

	int num;
	double d;
	char *str;
	exp_node_type_e type;
	get_exp_node_value(index,&type,&str,&num,&d);
	if(type == EXP_NODE_TYPE_CONST_INT){

		exp_var_t *new = exp_var_create(NULL);
		exp_var_t *tmp_var = exp_var_create(NULL);
		tmp_var->type = EXP_VAR_TYPE_POINT;
		tmp_var->var = exp_var_refer(new);
		exp_node_t *_left = exp_node_create(EXP_NODE_TYPE_VAR,tmp_var);
		result = evaluation(_left,value);
		exp_node_destroy(_left);

		exp_array_insert(var->array,new,num);
	}
	
exit:
	script_func_arg_release(argc,arg);
	return result;
}

static exp_node_t *array_append(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}
	
	exp_node_t *array = arg[0];
	exp_node_t *value = arg[1];
	exp_node_t *result = NULL;
	
	if(array->type != EXP_NODE_TYPE_VAR){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, first argument must be array type");
		goto exit;
	}

	exp_var_t *var = exp_var_point_take(array->var);
	if(var->type != EXP_VAR_TYPE_ARRAY){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, first argument must be array type");
		goto exit;
	}

	
	exp_var_t *new = exp_var_create(NULL);
	exp_node_t *_left = exp_node_create(EXP_NODE_TYPE_VAR,NULL);
	_left->var = exp_var_refer(new);
	result = evaluation(_left,value);
	exp_node_destroy(_left);

	if(var->array == NULL){
		var->array = exp_array_create();
	}

	exp_array_add(var->array,new);

	
exit:
	script_func_arg_release(argc,arg);
	return result;
}

static exp_node_t *array_delete(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *array = arg[0];
	exp_node_t *value = arg[1];
	exp_node_t *result = NULL;
	
	if(array->type != EXP_NODE_TYPE_VAR){
		SCRIPT_DEBUG_ERR("ArrayInsert param fail, first argument must be array type");
		goto exit;
	}

	exp_var_t *var = exp_var_point_take(array->var);
	if(var->type != EXP_VAR_TYPE_ARRAY){
		SCRIPT_DEBUG_ERR("ArrayDelete param fail, first argument must be array type");
		goto exit;
	}

	int index;
	exp_node_type_e type;
	get_exp_node_value(value,&type,NULL,&index,NULL);
	if(type != EXP_NODE_TYPE_CONST_INT){
		SCRIPT_DEBUG_ERR("ArrayDelete param fail, second argument must be int type");
		goto exit;
	}

	int ret = exp_var_array_delete(var,index);
	result = exp_node_create(EXP_NODE_TYPE_CONST_INT,0);
	result->number = ret;
	
exit:
	script_func_arg_release(argc,arg);
	return result;
}

static exp_node_t *sn_file_read(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 1){
		SCRIPT_DEBUG_ERR("FileRead param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *file = arg[0];	
	
	exp_node_type_e type;
	char *filename = NULL;
	get_exp_node_value(file,&type,&filename,NULL,NULL);
	if(filename == NULL){
		SCRIPT_DEBUG_WARN("Can't get file name");
		goto error;
	}

	FILE *fd = fopen(filename,"r");
	if(fd == NULL){
		// 取消文件打开失败的打印
		// SCRIPT_DEBUG_WARN("Open file %s fail",filename); 
		goto error;
	}

	int len;
	fseek(fd,0,SEEK_END);
	len = ftell(fd);
	char *buf = script_calloc(1,len+1);
	fseek(fd,0,SEEK_SET);
	fread(buf,1,len,fd);
	fclose(fd);
	exp_node_t *result = NULL;
	if(argc == 2 && strcmp("string",arg[1]->string) == 0){
		result = exp_node_create(EXP_NODE_TYPE_CONST_STRING,buf);		
	}else{
		exp_var_t *var = exp_var_parse(NULL,buf);
		result = exp_node_create(EXP_NODE_TYPE_VAR,var);
		if(var == NULL){
			SCRIPT_DEBUG_ERR("FileRead parse json fail");
			result->type = EXP_NODE_TYPE_ERR;
		}
		script_free(buf);
	}

	script_func_arg_release(2,arg);
	return result;

error:

	script_func_arg_release(2,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
	
}

static exp_node_t *sn_file_write(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("FileWrite param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *file = arg[0];
	exp_node_t *value = arg[1];

	exp_node_type_e type;
	char *filename = NULL;
	get_exp_node_value(file,&type,&filename,NULL,NULL);
	if(filename == NULL){
		goto error;
	}

	FILE *fd = fopen(filename,"w");
	if(fd == NULL){
		goto error;
	}

	char *str = exp_node_to_string(value);
	int ret = fwrite(str,1,strlen(str),fd);
	fclose(fd);

	script_free(str);
	script_func_arg_release(argc,arg);

	return exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)ret);

error:
	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
	
}

static exp_node_t *sn_file_append(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("FileApend param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *file = arg[0];
	exp_node_t *value = arg[1];

	exp_node_type_e type;
	char *filename = NULL;
	get_exp_node_value(file,&type,&filename,NULL,NULL);
	if(filename == NULL){
		goto error;
	}

	FILE *fd = fopen(filename,"a");
	if(fd == NULL){
		goto error;
	}

	char *str = exp_node_to_string(value);
	int ret = fwrite(str,1,strlen(str),fd);
	fclose(fd);

	script_free(str);
	script_func_arg_release(argc,arg);

	return exp_node_create(EXP_NODE_TYPE_CONST_INT,(void*)ret);
error:
	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
}


static exp_node_t *string_split(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("Split param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *str = arg[0];
	exp_node_t *sep = arg[1];

	exp_node_type_e str_type,sep_type;
	char *str_s = NULL,*sep_s = NULL;
	get_exp_node_value(str,&str_type,&str_s,NULL,NULL);
	get_exp_node_value(sep,&sep_type,&sep_s,NULL,NULL);

	if(str_type != EXP_NODE_TYPE_CONST_STRING || sep_type != EXP_NODE_TYPE_CONST_STRING){
		goto err;
	}

	int sep_len = strlen(sep_s);

	exp_var_t *array = exp_var_create(NULL);
	array->type = EXP_VAR_TYPE_ARRAY;

	char *start = str_s;	
	char *tmp;
	while(*start != 0){
		tmp = strstr(start,sep_s);
		exp_var_t *var = exp_var_create(NULL);
		var->type = EXP_VAR_TYPE_STRING;
		if(tmp == NULL){
			var->str = script_calloc(1,strlen(start)+1);
			strcpy(var->str,start);
			exp_var_add_child(array,var);
			break;
		}
		
		var->str = script_calloc(1,tmp - start + 1);
		strncpy(var->str,start,tmp-start);
		exp_var_add_child(array,var);
		start = tmp + sep_len;
	}

	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_VAR,array);
err:
	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
}

static exp_node_t *string_slice(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[3] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,3,arg);
	if(argc < 3){
		SCRIPT_DEBUG_ERR("Slice param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *_str = arg[0];
	exp_node_t *_start = arg[1];
	exp_node_t *_end = arg[2];

	exp_node_type_e str_type,start_type,end_type;
	char *str = NULL;
	int start,end;
	get_exp_node_value(_str,&str_type,&str,NULL,NULL);
	get_exp_node_value(_start,&start_type,NULL,&start,NULL);
	get_exp_node_value(_end,&end_type,NULL,&end,NULL);

	if(start_type != EXP_NODE_TYPE_CONST_INT ||
			end_type != EXP_NODE_TYPE_CONST_INT){
		goto err;
	}

	exp_var_t *array = NULL;
	if(str_type == EXP_NODE_TYPE_VAR){
		array = exp_var_point_take(_str->var);
		if(array->type != EXP_VAR_TYPE_ARRAY){
			goto err;
		}
	}else if(str_type != EXP_NODE_TYPE_CONST_STRING){
		goto err;
	}

	int s_len;
	if(str_type == EXP_NODE_TYPE_CONST_STRING){
		s_len = strlen(str);
	}else{
		s_len = exp_var_size(array);
	}

	if(s_len <= 0 || start >= s_len){
		goto err;
	}

	if(start < 0){
		start = s_len + start;
	}

	if(end < 0){
		end = s_len + end;
	}

	if(start > end){
		goto err;
	}

	if(end >= s_len){
		end = s_len -1;
	}

	if(str_type == EXP_NODE_TYPE_CONST_STRING){
		exp_node_t *result = exp_node_create(EXP_NODE_TYPE_CONST_STRING,NULL);
		result->string = script_calloc(1,end - start + 2);
		strncpy(result->string,str+start,end-start+1);
		script_func_arg_release(argc,arg);
		return result;
	}else{
		exp_var_t *tmp = array->var;
		int index = 0;
		exp_var_t *new = exp_var_create(NULL);
		new->type = EXP_VAR_TYPE_ARRAY;
		new->array = exp_array_create();
		int i;
		for(i = start; i <= end; i++){
			exp_array_add(new->array,exp_var_refer(array->array->p[i]));
		}

		return exp_node_create(EXP_NODE_TYPE_VAR,new);
	}

err:
	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
}

/********************************************************
 *	Regex(pattern,string)
 *
 *	return string array. 
 *		array[0]: match string; array[1-]: sub string
 * ******************************************************/
static exp_node_t *regex(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("Regex param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *pattern = arg[0];
	exp_node_t *str = arg[1];


	exp_node_type_e pattern_type,str_type;
	char *pattern_s = NULL,*str_s = NULL;
	get_exp_node_value(pattern,&pattern_type,&pattern_s,NULL,NULL);
	get_exp_node_value(str,&str_type,&str_s,NULL,NULL);

	if(pattern_type != EXP_NODE_TYPE_CONST_STRING || str_type != EXP_NODE_TYPE_CONST_STRING){
		goto err;
	}

	regex_t reg;
	int cflags = REG_EXTENDED;
	int ret = regcomp(&reg,pattern_s,cflags);
	if(ret){
		goto nomatch;
	}

	regmatch_t *pmatch = calloc(reg.re_nsub+1,sizeof(regmatch_t));
	ret = regexec(&reg,str_s,reg.re_nsub+1,pmatch,0);
	if(ret == REG_NOMATCH){
		regfree(&reg);
		goto nomatch;		
	}

	exp_var_t *array = exp_var_create(NULL);
	array->type = EXP_VAR_TYPE_ARRAY;

	int i;
	for(i = 0; i < reg.re_nsub+1; i++){
		exp_var_t *var = exp_var_create(NULL);
		var->type = EXP_VAR_TYPE_STRING;
		var->str = script_calloc(1,pmatch[i].rm_eo - pmatch[i].rm_so + 1);
		strncpy(var->str,str_s+pmatch[i].rm_so,pmatch[i].rm_eo-pmatch[i].rm_so);
		exp_var_add_child(array,var);
	}

	regfree(&reg);

	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_VAR,array);

nomatch:

	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);

err:
	script_func_arg_release(argc,arg);
	return NULL;
}

static exp_node_t *format(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *arg[2] = {0};
	int argc = 0;
	argc = script_func_arg_get(args,block_stack,2,arg);
	if(argc < 2){
		SCRIPT_DEBUG_ERR("Format param fail, argument is too less");
		script_func_arg_release(argc,arg);
		return NULL;
	}

	exp_node_t *src = arg[0];
	exp_node_t *format = arg[1];

	exp_node_type_e src_t,format_t;
	int num;
	double d;
	char *src_s,*format_s;

	get_exp_node_value(src,&src_t,&src_s,&num,&d);
	get_exp_node_value(format,&format_t,&format_s,NULL,NULL);
	if(format_t != EXP_NODE_TYPE_CONST_STRING){
		goto err;
	}
	exp_node_t *result = NULL;

	char buf[512] = {0};
	switch(src_t){
		case EXP_NODE_TYPE_CONST_INT:
			sprintf(buf,format_s,num);	
			break;
		case EXP_NODE_TYPE_CONST_DOUBLE:
			sprintf(buf,format_s,d);
			break;
		case EXP_NODE_TYPE_CONST_STRING:
			sprintf(buf,format_s,src_s);
			break;
		default:
			goto err;
	}

	result = exp_node_create(EXP_NODE_TYPE_CONST_STRING,buf);
	script_func_arg_release(argc,arg);
	return result;
err:
	script_func_arg_release(argc,arg);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);

}

static exp_node_t *run_code(TFly_list_t *args, script_stack_t *block_stack,void *param)
{
	if(args == NULL || block_stack == NULL){
		return NULL;		
	}

	exp_node_t *_code = TFly_list_get_first(args);
	if(_code == NULL){
		return NULL;
	}

	exp_node_t *code = expression_calc(_code,block_stack);	
	CHECK_RESULT(code);

	exp_node_type_e type;
	char *str;
	get_exp_node_value(code,&type,&str,NULL,NULL);
	if(type != EXP_NODE_TYPE_CONST_STRING){
		goto err;
	}

	script_t *script = script_script_create();
	script_stack_Push(script->code_stack,script->main_code);
	script_parse_from_string(script,str);
	script_stack_Pop(script->code_stack);
	
	exp_node_t *result = run_block(script->main_code,block_stack,NULL);

	script_destroy(script);
	exp_node_destroy(code);
	return result;
err:
	exp_node_destroy(code);
	return exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);

}

/********************************************************
 *	内置函数
 *
 * ******************************************************/
const static c_func_t all_func[] = {
	/********************************************************
	 *
	 * ******************************************************/
	{"Print", sn_printf,NULL},

	/********************************************************
	 *	内置函数 NewStruct
	 *		创建一个结构体变量
	 *	NewStruct()
	 *	NewStruct("{\"name\":\"test\"}")
	 *	也可以用于创建数组
	 *	NewStruct("[1,2]")
	 * ******************************************************/
	{"NewStruct",new_struct,NULL},

	{"MemberDelete", struct_member_delete,NULL},

	/********************************************************
	 *	内置函数 Random
	 *		随机数生成函数
	 * ******************************************************/
	{"Random",sn_random,NULL},

	{"ToNumber",string_to_number,NULL},
	{"ToString",sn_to_string,NULL},

	/********************************************************
	 *	内置函数 Length
	 *		获取变量长度
	 * ******************************************************/
	{"Length",sn_length,NULL},

	{"Sleep",sn_sleepm,NULL},
	{"Time",sn_time,NULL},
	{"VarType",sn_var_type_get,NULL},
	{"ArrayInsert",array_insert,NULL},
	{"ArrayAppend",array_append,NULL},
	{"ArrayDelete",array_delete,NULL},
	{"FileRead",sn_file_read,NULL},
	{"FileWrite",sn_file_write,NULL},
	{"FileAppend",sn_file_append,NULL},

	{"Split",string_split,NULL},
	{"Slice",string_slice,NULL},
	{"Regex",regex,NULL},
	{"RunCode",run_code,NULL},
	{"Format",format,NULL},

};

exec_func_t *script_func_node_create(void)
{
	exec_func_t *func = script_calloc(1,sizeof(exec_func_t));
	if(func == NULL){
		return NULL;
	}

	func->args = TFly_list_create();

	return func;
}

void script_func_node_destroy(exec_func_t *func)
{
	if(func == NULL){
		return;
	}

	if(func->type == 0){
		if(func->exp->type == EXEC_FUNC_TYPE_C){
			const struct script_keyword_t *keyword = find_keyword_by_func(func->exp);
			if(keyword && keyword->destroy){
				keyword->destroy(func);
				return;
			}
		}
	}else{
		exp_node_list_destroy(func->exp);
	}

	if(func->args){
		exp_node_t *node = TFly_list_del_first(func->args);
		while(node){
			exp_node_list_destroy(node);
			node = TFly_list_del_first(func->args);
		}
		TFly_list_destroy(func->args);
	}
	script_free(func);
}

void c_func_destroy(c_func_t *func)
{
	if(func){
		script_free(func);
	}
}

void exp_func_destroy(exp_func_t *func)
{
	if(func == NULL){
		return;
	}

	if(func->type == EXEC_FUNC_TYPE_C){
		c_func_destroy(func->c_func);
	}else{
		script_func_destroy(func->s_func);
	}
	script_free(func);
}

int script_c_func_register(script_t *script,script_c_func cfunc, char *func_name,void *param)
{
	if(script == NULL || cfunc == NULL || func_name == NULL){
		SCRIPT_DEBUG_ERR("Param error!");
		return SCRIPT_ERR_PARAM;
	}

	c_func_t *func;
	if(strlen(func_name) >= sizeof(func->name)){
		SCRIPT_DEBUG_ERR("function name is too long. Max length is %ld",sizeof(func->name));
		return SCRIPT_ERR_PARAM;
	}

	func = script_calloc(1,sizeof(c_func_t));

	func->func = cfunc;
	func->param = param;
	strcpy(func->name,func_name);
	exp_func_t *exp_func = script_calloc(1,sizeof(exp_func_t));
	exp_func->type = EXEC_FUNC_TYPE_C;
	exp_func->c_func = func;
	TFly_list_add(script->funcs,exp_func);

	exp_var_t *var = exp_var_create(func_name);
	var->type = EXP_VAR_TYPE_FUNCTION;
	var->func = exp_var_func_create(exp_func,NULL);
	exp_var_struct_add(script->exec_block->vars,var);

	return 0;
}

int script_c_func_unregister(script_t *script, char *func_name)
{
	if(script == NULL || func_name == NULL){
		return SCRIPT_ERR_PARAM;
	}

	return 0;
}

int script_c_func_register_include(script_t *script,char *inc_var_name, script_c_func cfunc, char *func_name, void *param)
{
	include_data_t *inc = script_include_get(script,inc_var_name);
	if(inc == NULL){
		SCRIPT_DEBUG_ERR("Can't find include %s",inc_var_name);
		return -1;
	}

	c_func_t *func;
	if(strlen(func_name) >= sizeof(func->name)){
		SCRIPT_DEBUG_ERR("function name is too long. Max length is %ld",sizeof(func->name));
		return SCRIPT_ERR_PARAM;
	}

	func = script_calloc(1,sizeof(c_func_t));
	func->func = cfunc;
	func->param = param;
	strcpy(func->name,func_name);
	exp_func_t *exp_func = script_calloc(1,sizeof(exp_func_t));
	exp_func->type = EXEC_FUNC_TYPE_C;
	exp_func->c_func = func;
	TFly_list_add(inc->inc->script->funcs,exp_func);

	exp_var_t *var = exp_var_create(func_name);
	var->type = EXP_VAR_TYPE_FUNCTION;
	var->func = exp_var_func_create(exp_func,NULL);
	exp_var_struct_add(inc->block->vars,var);
	return 0;
}

int script_default_func_register(script_c_func cfunc, char *func_name,void *param)
{
	if(cfunc == NULL || func_name == NULL){
		SCRIPT_DEBUG_ERR("Param error!");
		return SCRIPT_ERR_PARAM;
	}

	c_func_t *func;
	if(strlen(func_name) >= sizeof(func->name)){
		SCRIPT_DEBUG_ERR("function name is too long. Max length is %ld",sizeof(func->name));
		return SCRIPT_ERR_PARAM;
	}

	if(default_func_list == NULL){
		script_default_func_init();
	}

	func = script_calloc(1,sizeof(c_func_t));

	func->func = cfunc;
	func->param = param;
	strcpy(func->name,func_name);
	exp_func_t *exp_func = script_calloc(1,sizeof(exp_func_t));
	exp_func->type = EXEC_FUNC_TYPE_C;
	exp_func->c_func = func;
	TFly_list_add(default_func_list,exp_func);

	exp_var_t *var = exp_var_create(func_name);
	var->type = EXP_VAR_TYPE_FUNCTION;
	var->func = exp_var_func_create(exp_func,NULL);
	exp_var_struct_add(&default_func_var,var);

	return 0;
}

int script_default_func_init(void)
{
	if(default_func_list){
		return 0;
	}

	default_func_list = TFly_list_create();


	int len = sizeof(all_func) / sizeof(c_func_t);
	int i;
    for (i = 0; i < len; i++) {
		exp_func_t *func = script_calloc(1,sizeof(exp_func_t));
		func->c_func = (c_func_t*)&all_func[i];
		func->type = EXEC_FUNC_TYPE_C;
		TFly_list_add(default_func_list,func);
		exp_var_t *var = exp_var_create(func->c_func->name);
		var->type = EXP_VAR_TYPE_FUNCTION;
		var->func = exp_var_func_create(func,NULL);
		var->refer = DEFAULT_FUNC_REFER;
		exp_var_struct_add(&default_func_var,var);
    }

	return 0;
}

exp_var_t *script_default_func_var_get(char *name)
{
	exp_var_t *var = exp_var_struct_get_var(&default_func_var,name);
	return var;
}

void script_default_func_uninit(void)
{
	//exp_var_destroy(default_func_var.var);
	exp_var_t *var = TFly_list_get_first(&default_func_var.object->children);
	while(var){
		var->refer = 0;
		var = TFly_list_get_next(&default_func_var.object->children);
	}
	exp_object_destroy(default_func_var.object);

	if(default_func_list){
		exp_func_t *func = TFly_list_del_first(default_func_list);
		while(func){
			script_free(func);
			func = TFly_list_del_first(default_func_list);

		}
		TFly_list_destroy(default_func_list);
		default_func_list = NULL;
	}
}
